package com.monitor.config;

import org.apache.shiro.mgt.SecurityManager;
import org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor;
import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;


/**
 * Shiro配置.
 *
 * @author Li Zhiyuan
 * @since 2020-11-10
 */

//reaml->SecurityManager->filter.在过滤器中，我们需要定义一个shiroFactoryBean,然后将SecurityManager添加进来
//默认登录的url:身份认证失败会访问该url
//认证成功之后要跳转的url
//权限认证失败会访问该url
//需要拦截或者放行的url：这些都放在一个map中

//Filter 说明
//anon 开放权限，可以理解为匿名用户或游客，可以直接访问的
//authc 需要身份认证的
//logout 注销，执行后会直接跳转到setLoginUrl()设置的url，即登录页面
//roles[admin] 参数可以写多个，表示是某个或某些角色才能通过，多个参数时写roles["admin,user"],当有多个参数时必须每个参数都通过才算通过
//perms[user] 参数可写多个，表示需要某个或某些权限才能通过，多个参数时写perms["user,admin"],当有多个参数时必须每个参数都通过才算通过
@Configuration
public class ShiroConfig {
    private static final Logger logger = LoggerFactory.getLogger(ShiroConfig.class);

    @Autowired
    private PermsMap permsMap;

    /**
     * 注入自定义的realm
     *
     * @return MyRealm
     */
    @Bean
    public MyRealm myAuthRealm() {
        MyRealm myRealm = new MyRealm();
        logger.info("======myRealm注册完成=====");
        return myRealm;
    }

    /**
     * 注入安全管理器
     *
     * @return SecurityManager
     */
    @Bean
    public SecurityManager securityManager() {
        //将自定义realm加进来
        DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager(myAuthRealm());
        logger.info("===securityManager注册完成====");
        return securityManager;
    }

    /**
     * 注入Shiro过滤器
     *
     * @param securityManager 安全管理器
     * @return ShiroFilterFactoryBean
     */
    @Bean
    public ShiroFilterFactoryBean shiroFilterFactoryBean(SecurityManager securityManager) {

        //LinkedHashMap是有序的，进行顺序拦截配置
        Map<String, String> filterChainMap = new LinkedHashMap<>();
//        这个map有顺序，按照先后顺序必须
        //配置可以匿名访问的地址，可以根据实际情况自己添加，放行一些静态资源等，anon表示放行
        filterChainMap.put("/css/**", "anon");
        filterChainMap.put("/imgs/**", "anon");
        filterChainMap.put("/js/**", "anon");

        //swagger
        filterChainMap.put("/swagger-ui.html", "anon");
        filterChainMap.put("/swagger/**", "anon");
        filterChainMap.put("/webjars/**", "anon");
        filterChainMap.put("/swagger-resources/**", "anon");
        filterChainMap.put("/v2/**", "anon");
        filterChainMap.put("/static/**", "anon");


        //配置logout过滤器
        filterChainMap.put("/user/logout", "logout");
        //登录url放行
//        filterChainMap.put("/login", "anon");
//         "/user/admin" 开头的需要身份认证，authc表示要身份认证
//        filterChainMap.put("/user/admin*", "authc");
//         "/user/student" 开头的需要角色认证，是"admin"才允许
//        filterChainMap.put("/user/student*/**", "roles[admin]");
//         "/user/teacher" 开头的需要权限认证，是“user:create”才允许
//        filterChainMap.put("/user/teacher*/**", "perms[\"user:create\"]");

        filterChainMap.put("/favicon.ico", "anon");
        filterChainMap.put("/user/login", "anon");
        filterChainMap.put("/sediment/upload","anon");

        //动态权限注入
        List<Map<String, String>> perms = permsMap.getPerms();
        perms.forEach(l -> filterChainMap.put(l.get("url"), l.get("permission")));

//        filterChainMap.put("/**", "authc");


        //定义shiroFactoryBean
        ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
        //设置自定义的securityManager
        shiroFilterFactoryBean.setSecurityManager(securityManager);
        //设置默认登录的url，身份认证失败会访问该url
        shiroFilterFactoryBean.setLoginUrl("/login");
        //设置成功之后要跳转的链接
        shiroFilterFactoryBean.setSuccessUrl("/user/login");
        //设置未授权界面，权限认证会失败访问该url
        shiroFilterFactoryBean.setUnauthorizedUrl("/unauthorized");


        //设置shiroFilterFactoryBean的FilterChainDefinitionMap
        shiroFilterFactoryBean.setFilterChainDefinitionMap(filterChainMap);
        logger.info("====shiroFilterFactoryBean注册完成====");
        return shiroFilterFactoryBean;


    }


    //避免注解无效
    @Bean
    @ConditionalOnMissingBean
    public DefaultAdvisorAutoProxyCreator defaultAdvisorAutoProxyCreator() {
        DefaultAdvisorAutoProxyCreator autoProxyCreator = new DefaultAdvisorAutoProxyCreator();
        autoProxyCreator.setProxyTargetClass(true);
        return autoProxyCreator;
    }

    @Bean
    public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(SecurityManager securityManager) {
        AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor = new AuthorizationAttributeSourceAdvisor();
        authorizationAttributeSourceAdvisor.setSecurityManager(securityManager);
        return authorizationAttributeSourceAdvisor;
    }
}
